package com.codemes.happylist.modules.pdf.view;

import cn.hutool.core.comparator.PinyinComparator;
import javafx.collections.ObservableList;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TreeItem;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

import java.util.ArrayList;
import java.util.List;

/**
 * @author nscoffee
 */
@EqualsAndHashCode(callSuper = true)
@Data
@Slf4j
public class DomTreeItem<T extends Node> extends TreeItem<Node> {

    private org.w3c.dom.Node node;

    public DomTreeItem(T node){
        super(node);
        this.node = node;
        initGraphic();
        initExpandEvent();
    }

    private Boolean expand = false;

    @Override
    public String toString(){
        return "";
    }

    private void initGraphic() {
        HBox hBox = new HBox();
        ObservableList<javafx.scene.Node> children = hBox.getChildren();

        String tagName = node.getNodeName().toLowerCase();
        if(tagName.equals("#text")){
            children.add(buildNode(node.getNodeValue(),"-fx-text-fill: green"));
            setGraphic(hBox);
            return;
        }
        children.add(buildNode("<","-fx-text-fill: blue"));
        children.add(buildNode(tagName,"-fx-text-fill: #8552a1"));
        NamedNodeMap namedNodeMap = node.getAttributes();
        if(null!=namedNodeMap){
            int attrLen = namedNodeMap.getLength();
            for(int j=0;j<attrLen;j++){
                Node attrNode = namedNodeMap.item(j);
                children.add(buildNode(" "+attrNode.getNodeName(),"-fx-text-fill: #b36d41"));
                children.add(buildNode("=","-fx-text-fill: #1d953f"));
                children.add(buildNode("\"","-fx-text-fill: #005344"));
                children.add(buildNode(attrNode.getNodeValue(),"-fx-text-fill: #53261f"));
                children.add(buildNode("\"","-fx-text-fill: #005344"));
            }
        }
        if(node.getChildNodes().getLength()>0){
            if(Boolean.TRUE.equals(expand)){
                children.add(buildNode(">","-fx-text-fill: blue"));
            }else{
                children.add(buildNode(">","-fx-text-fill: blue"));
                children.add(buildNode("...","-fx-text-fill: #145b7d"));
                buildEndTagGraphic(hBox,tagName);
            }
        } else {
            children.add(buildNode("/>","-fx-text-fill: blue"));
        }
        setGraphic(hBox);
    }

    private HBox buildEndTagGraphic(HBox hBox, String tagName){
        if(null==hBox){
            hBox = new HBox();
        }
        ObservableList<javafx.scene.Node> children = hBox.getChildren();
        children.add(buildNode("</","-fx-text-fill: blue"));
        children.add(buildNode(tagName.toLowerCase(),"-fx-text-fill: #8552a1"));
        children.add(buildNode(">","-fx-text-fill: blue"));
        return hBox;
    }
    private Label buildNode(String content, String style){
        Label text = new Label(content);
        if(!StringUtils.isEmpty(style)){
            text.setStyle(style);
        }
        return text;
    }

    private void initExpandEvent(){
        if(node.getChildNodes().getLength()>0){
            expandedProperty().addListener((observableValue, aBoolean, t1) -> {
                setExpand(t1);
                initGraphic();
                TreeItem<Node> parent = this.getParent();
                if(null==parent){
                    return;
                }
                if(Boolean.TRUE.equals(t1)){
                    Node endTag = node.getOwnerDocument().createTextNode("</"+node.getNodeName().toLowerCase()+">");
                    HBox hBox = buildEndTagGraphic(null, node.getNodeName());
                    DomTreeItem<Node> nodeDomTreeItem = new DomTreeItem<>(endTag);
                    nodeDomTreeItem.setGraphic(hBox);
                    int childIndex = parent.getChildren().indexOf(this);
                    parent.getChildren().add(childIndex+1,nodeDomTreeItem);
                }else{
                    parent.getChildren().remove(nextSibling());
                }
            });
        }
    }

    public String toHtml() {
        String tagName = node.getNodeName().toLowerCase();
        if(tagName.equals("#text")){
            return node.getNodeValue();
        }
        StringBuilder builder = new StringBuilder("<");
        builder.append(tagName);
        NamedNodeMap namedNodeMap = node.getAttributes();
        if(null!=namedNodeMap){
            int attrLen = namedNodeMap.getLength();
            for(int j=0;j<attrLen;j++){
                Node attrNode = namedNodeMap.item(j);
                builder.append(" ").append(attrNode.getNodeName()).append("=\"").append(attrNode.getNodeValue()).append("\" ");
            }
        }
        if(node.getChildNodes().getLength()>0){
            builder.append(endTag());
        } else {
            builder.append("/>");
        }
        return builder.toString();
    }

    private String endTag(){
        StringBuilder builder = new StringBuilder();
        if(Boolean.TRUE.equals(expand)){
            builder.append(">");
        }else{
            builder.append(">...");
            builder.append("</").append(node.getNodeName().toLowerCase()).append(">");
        }
        return  builder.toString();
    }
}
